#include "tbcore/base/initializer.hpp"

#include <algorithm>

TB_NAMESPACE_BEGIN

 Initializer::Initializer() {}
 
 Initializer::~Initializer() {}
 
 void Initializer::RegisterInitializer(
 	const _STD string& name, 
 	const InitializerContext::InitializerFunction& func, 
 	const _STD vector<_STD string>& prerequisites,
 	const _STD vector<_STD string>& depends) {
 	IntializerGraph::IntializerGraphNode& node = graph.nodes[name];
 	node.func = func;
 
 	for (_STD vector<_STD string>::const_iterator it = prerequisites.begin();
 		it != prerequisites.end();
 		++it) {
 		node.prerequisites.insert(*it);
 	}
 
 	for (std::vector<std::string>::const_iterator it = depends.begin();
 		it != depends.end();
 		++it) {
 		graph.nodes[*it].prerequisites.insert(name);
 	}
 }
 
 Result Initializer::Execute(const InitializerContext& contex) {
	typedef _STD vector<_STD pair<std::string, int> > SortedNodesT;

	SortedNodesT sortedNodes;
 	SortByPrerequistes(sortedNodes);
 
	for (SortedNodesT::iterator it = sortedNodes.begin();
 		it != sortedNodes.end();
 		++it) {
 		IntializerGraph::NodesMapT::iterator findIt = graph.nodes.find(it->first);
 
		if (findIt != graph.nodes.end() && findIt->second.func) {
			Result r = findIt->second.func(contex);
 			if (r.HasError()) {
 				return r;
 			}
 		}
 	}
 	return Result();
 }
 
 namespace {

void IncDependCount(
 	unordered_map<_STD string, int>& m, const _STD string& name) {
 	unordered_map<_STD string, int>::iterator it = m.find(name);
 	if (it == m.end()) {
		m.insert(_STD make_pair(name, 1));
 	} else {
 		it->second++;
 	}
}
 
void RecursiveIncDependCount(
 	unordered_map<std::string, int>& m, 
 	IntializerGraph& g, 
 	IntializerGraph::IntializerGraphNode& node) {
 	for (unordered_set<_STD string>::iterator it = node.prerequisites.begin();
 		it != node.prerequisites.end();
 		++it) {
 		IncDependCount(m, *it);
 		IntializerGraph::NodesMapT::iterator findIter = g.nodes.find(*it);
 		if (findIter != g.nodes.end()) {
 			RecursiveIncDependCount(m, g, findIter->second);
 		}
 	}
}

} // namespace 
 
 void Initializer::SortByPrerequistes(_STD vector<_STD pair<_STD string, int> >& sortedNodes) {
 	unordered_map<_STD string, int> depCountMap;
 
 	typedef IntializerGraph::IntializerGraphNode GraphNodeT;
 	typedef unordered_map<_STD string, GraphNodeT>::iterator NodeIteratorT;
 
 	for (NodeIteratorT it = graph.nodes.begin();
 		it != graph.nodes.end();
 		++it) {
 		IncDependCount(depCountMap, it->first);
 		RecursiveIncDependCount(depCountMap, graph, it->second);
 	}
 
 	for (unordered_map<_STD string, int>::iterator it = depCountMap.begin();
 		it != depCountMap.end();
 		++it) {
 		sortedNodes.push_back(std::make_pair(it->first, it->second));
 	}
 
 	std::stable_sort(sortedNodes.begin(), sortedNodes.end(), 
 		[](const _STD pair<std::string, int>& lhs, const _STD pair<_STD string, int>& rhs) {
 			return lhs.second > rhs.second;
 		}
 	);
 }

TB_NAMESPACE_END